package cn.kai.ymcc.service.impl;

import cn.kai.ymcc.constants.CommonConstants;
import cn.kai.ymcc.constants.SmsCodeConstants;
import cn.kai.ymcc.constants.YmccBusinessError;
import cn.kai.ymcc.domain.MessageSms;
import cn.kai.ymcc.dto.RedisRegisterDto;
import cn.kai.ymcc.dto.RegisterSmsDto;
import cn.kai.ymcc.exception.GlobalException;
import cn.kai.ymcc.service.IMessageSmsService;
import cn.kai.ymcc.service.IVerifyCodeService;
import cn.kai.ymcc.util.AssertUtil;
import cn.kai.ymcc.util.StrUtils;
import cn.kai.ymcc.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @Author Kai
 * @Date 2022/6/15 19:35
 * @PackageName:cn.kai.basic.service.impl
 * @ClassName: VerifyCodeServiceImpl
 * @Description: 生成验证码业务层实现类
 * @Version 1.0
 */

@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private SmsCodeConstants smsCodeConstants;

    @Autowired
    private IMessageSmsService messageSmsService;

    /**
     * 一：校验
     *  1.空校验
     *  2.格式校验
     * 二：验证码
     *  1.校验手机号是否发送过验证码
     *  2.从redis拿到了
     *    2.1 没有过重发时间，使劲骂
     *    2.2 过了重发时间，使用还未过期的码儿
     *  3.拿不到
     * 3.1.生成验证码
     * 3.2.存储验证码
     * 3.3.发送验证码短信
     * 3.4.存储发送信息到数据库
     * @param key
     * @return
     */
    @Override
    public String imageCode(String key) {
        if(!StringUtils.hasLength(key)){
            throw new GlobalException(YmccBusinessError.COMMON_ERROR_EXCEPTION_NOT_NULL_IMGCODEKEY.getMessage(),YmccBusinessError.COMMON_ERROR_EXCEPTION_NOT_NULL_IMGCODEKEY.getCode());
        }
        //生成4位随机数
        String code = StrUtils.getComplexRandomString(4);
        //保存redis，设置过期时间 key为前端传递的uuid，value为code
        redisTemplate.opsForValue().set(key,code,5, TimeUnit.MINUTES);
        //使用2d把code画成图，把图使用Base64编码成字符串并返回
        return VerifyCodeUtils.verifyCode(100,38,code);
    }

    /**
     * 短信验证码
     * @param dto
     */
    @Override
    public void smsCode(RegisterSmsDto dto) {
//        一：校验
//        1.空校验
        AssertUtil.isNotEmpty(dto.getMobile(),YmccBusinessError.COMMON_ERROR_EXCEPTION_PHONE_NO_EMPTY.getMessage());
        AssertUtil.isNotEmpty(dto.getImageCodeKey(),YmccBusinessError.COMMON_ERROR_EXCEPTION_NOT_NULL_IMGCODEKEY.getMessage());
        //判断用户是否输入了图形验证码
        AssertUtil.isNotEmpty(dto.getImageCodeValue(),YmccBusinessError.COMMON_ERROR_EXCEPTION_NOT_NULL_IMGCODEVALUE.getMessage());
        //判断用户输入的图形验证码是否正确
        boolean imageCode_boo = dto.getImageCodeValue().equalsIgnoreCase(redisTemplate.opsForValue().get(dto.getImageCodeKey()).toString());
        AssertUtil.isTrue(imageCode_boo,YmccBusinessError.COMMON_ERROR_EXCEPTION_IMGCODEVALUE_MISTAKE.getMessage());
//        2.@TODO     黑名单
        AssertUtil.isPhone(dto.getMobile(),YmccBusinessError.COMMON_ERROR_EXCEPTION_PHONE_ILLEGAL.getMessage());//手机号不合法
//        二：验证码
        String key = String.format(CommonConstants.REGISTER_PHONE_PRIFIX, dto.getMobile());//register:158234234
        Date now = new Date();
//        1.校验手机号是否发送过验证码
        Object o = redisTemplate.opsForValue().get(key);
        String code = null;
        if(o != null){
//        2.从redis拿到了
            RedisRegisterDto registerDto = (RedisRegisterDto) o;
            boolean canSend = (now.getTime() - registerDto.getTime()) / 1000 > smsCodeConstants.getInterval();
//        2.1 没有过重发时间，使劲骂
            AssertUtil.isTrue(canSend,YmccBusinessError.COMMON_ERROR_EXCEPTION_SERIOUS.getMessage());
//        2.2 过了重发时间，使用还未过期的码儿
            code = registerDto.getCode();
        }else{
            //        3.拿不到
//        3.1.生成验证码
            code = StrUtils.getRandomString(smsCodeConstants.getSize());
        }
//        3.2.存储验证码
        //String codeValue = code + ":"+System.currentTimeMillis();
        RedisRegisterDto redisRegisterDto = new RedisRegisterDto(code, now.getTime());
        redisTemplate.opsForValue().set(key,redisRegisterDto,smsCodeConstants.getTimeout(), TimeUnit.SECONDS);
//        3.3.发送验证码短信
        String message = String.format(smsCodeConstants.getSmsmessage(), code);

        log.info(message);
//        3.4.存储发送信息到数据库
        saveMessageSms(now, code, message);
    }


    private void saveMessageSms(Date now, String code,String message) {
        MessageSms messageSms = new MessageSms();
        messageSms.setContent(message);
        messageSms.setSendTime(now);
        messageSms.setTitle(smsCodeConstants.getTitle());
        // 获取请求体 request
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        messageSms.setIp(request.getRemoteAddr());//获取IP地址
        messageSmsService.insert(messageSms);
    }
}
